﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using Fleck;
using TuringCup;
using System.IO;
using System.IO.Compression;

namespace GameServer
{
    /// <summary>
    /// 控制一场游戏进行的类
    /// </summary>
    class GameControl
    {
        /// <summary>
        /// 游戏主线程
        /// </summary>
        Thread game;

        /// <summary>
        /// Webscoket 连接
        /// </summary>
        List<IWebSocketConnection> sockets;

        /// <summary>
        /// 游戏状态
        /// </summary>
        GameState gs = new GameState();

        /// <summary>
        /// 上一tick结束时间
        /// </summary>
        int last_tick;

        List<AI_Container> AIs = new List<AI_Container>();

        /// <summary>
        /// 游戏录像
        /// </summary>
        StreamWriter replay = null;

        /// <summary>
        /// 游戏启动时间
        /// </summary>
        DateTime game_start_time = new DateTime();

        List<String> AI_filenames = new List<string>();

        String battle_filename = "";

        AutoResetEvent game_running = null;
        /// <summary>
        /// 启动游戏
        /// </summary>
        public void Start()
        {
            var stream = System.IO.File.OpenRead("map.json");
            gs = GameState.Load(stream);
            gs.gconfig = new GameConfig();
            gs.team_name = new Dictionary<int, string>();
            game = new Thread(game_run);
            for (int i = 0; i < AI_filenames.Count; i++)
            {
                AIs.Add(new AI_Container(i + 1));
                AIs[i].LoadDll(System.Environment.CurrentDirectory + @"\AIs\" + AI_filenames[i]);
            }
            //AIs.Add(new AI_Container(1));
            //AIs.Add(new AI_Container(2));
            //AIs.Add(new AI_Container(3));
            //AIs.Add(new AI_Container(4));
            //AIs[0].LoadDll(System.Environment.CurrentDirectory + @"\AIs\SampleAI.dll");
            //AIs[1].LoadDll(System.Environment.CurrentDirectory + @"\AIs\SampleAI.dll");
            //AIs[2].LoadDll(System.Environment.CurrentDirectory + @"\AIs\SampleAI.dll");
            //AIs[3].LoadDll(System.Environment.CurrentDirectory + @"\AIs\SampleAI.dll");
            battle_filename = DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss");
            foreach (AI_Container ai in AIs)
            {
                gs.team_name.Add(ai.side, ai.team_name);
                battle_filename += "_" + ai.team_name;
            }
            String replay_filename = battle_filename + ".gz";
            game_start_time = DateTime.Now;
            System.IO.Directory.CreateDirectory(System.Environment.CurrentDirectory + @"\replay");
            FileStream fs = new FileStream(System.Environment.CurrentDirectory + @"\replay\" + replay_filename, FileMode.Create);
            GZipStream gzip_stream = new GZipStream(fs, CompressionLevel.Optimal);
            replay = new StreamWriter(gzip_stream);
        }
        public void Start(AutoResetEvent game_running)
        {
            Start();
            this.game_running = game_running;
        }

        /// <summary>
        /// 暂停游戏
        /// </summary>
        public void Pause()
        {

        }
        /// <summary>
        /// 恢复游戏
        /// </summary>
        public void Continue()
        {
            last_tick = Environment.TickCount;
            game.Start();
        }
        /// <summary>
        /// 停止游戏
        /// </summary>
        public void Stop()
        {
            if (game != null)
                game.Abort();
        }
        /// <summary>
        /// 游戏逻辑主循环
        /// </summary>
        void game_run()
        {
            while (gs.tick_count < 100 * 10)//主循环
            {
                lock (gs)//加锁
                {
                    gs.tick();//执行游戏逻辑
                    replay.WriteLine(gs.Serialize());
                    for (int i = 0; i < AIs.Count; i++)
                    {
                        AI_Commands cmd = null;
                        int ai_start_time = Environment.TickCount;
                        try
                        {
                            Console.WriteLine();
                            Console.WriteLine(AIs[i].team_name + "is Running");
                            cmd = AIs[i].RunAI(gs.Serialize());
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine("Runtime Error in " + AIs[i].team_name);
                            Console.WriteLine(e.Message);
                            Console.WriteLine(e.InnerException.Message);
                        }
                        Console.WriteLine(AIs[i].team_name + "takes " + (Environment.TickCount - ai_start_time).ToString() + " ms");
                        if (cmd != null)
                            gs.AI_Order(cmd, AIs[i].side);

                    }
                    //向所有socket 发送战场信息
                    foreach (var socket in sockets.ToList())
                    {
                        socket.Send(gs.Serialize());
                    }
                }
                int now = Environment.TickCount;
                last_tick += gs.gconfig.game_speed;
                Thread.Sleep(Math.Max(0, last_tick - now));
                replay.Flush();
            }
            Console.WriteLine("Game Over");
            replay.WriteLine(gs.Serialize());
            replay.Close();
            //记录比分
            System.IO.Directory.CreateDirectory(System.Environment.CurrentDirectory + @"\scores");
            Dictionary<int,Double> scores = getScores();
            String result = "";
            foreach (var ai in AIs)
            {
               result += ai.team_name +"\t" + scores[ai.side].ToString() + "\r\n";
            }
            System.IO.File.WriteAllText(System.Environment.CurrentDirectory + @"\scores\" + battle_filename + ".log", result);
            if (game_running != null)
                game_running.Set();
        }
        public GameControl(List<IWebSocketConnection> sockets)
        {
            this.sockets = sockets;
            gs = new GameState();
        }
        public GameControl(List<IWebSocketConnection> sockets, List<String> ai_files)
            : this(sockets)
        {
            AI_filenames = new List<string>(ai_files);
        }
        /// <summary>
        /// 获得各方游戏得分
        /// </summary>
        /// <returns>字典,表示各方得分</returns>
        public Dictionary<int, double> getScores()
        {
            Dictionary<int, double> scores = new Dictionary<int, double>();
            lock (gs)
            {
                foreach (var cell in gs.cells)
                {
                    if (!scores.ContainsKey(cell.side))
                        scores.Add(cell.side, 0.0);
                    scores[cell.side] += cell.hp;
                }
                foreach (var tent in gs.tents)
                    scores[gs.cells[tent.begin].side] += (tent.len1 + tent.len2) * gs.gconfig.t_density;
            }
            return scores;
        }

    }
}
